/**
 * test_app.c - 用于测试钩子框架的示例应用程序
 *
 * 此程序执行各种可被钩子框架拦截的操作，
 * 如文件I/O、网络连接等。
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <signal.h>
#include <time.h>
#include <openssl/ssl.h>
#include <openssl/err.h>

#define TEST_PORT 8080
#define TEST_BUFFER_SIZE 1024

/**
 * 测试文件I/O操作
 */
static void test_file_io(void) {
    printf("\n=== 测试文件I/O操作 ===\n");
    
    /* 测试低级文件操作 */
    printf("正在使用open()打开文件'test_output.txt'...\n");
    int fd = open("test_output.txt", O_WRONLY | O_CREAT | O_TRUNC, 0644);
    if (fd < 0) {
        perror("打开文件失败");
    } else {
        const char *data = "这是使用write()写入的测试数据。\n";
        printf("正在使用write()写入数据...\n");
        ssize_t written = write(fd, data, strlen(data));
        printf("已写入%zd字节\n", written);
        
        printf("正在使用close()关闭文件...\n");
        close(fd);
    }
    
    /* 测试高级文件操作 */
    printf("\n正在使用fopen()打开文件'test_output2.txt'...\n");
    FILE *fp = fopen("test_output2.txt", "w");
    if (!fp) {
        perror("打开文件失败");
    } else {
        const char *data = "这是使用fprintf()写入的测试数据。\n";
        printf("正在使用fprintf()写入数据...\n");
        fprintf(fp, "%s", data);
        
        printf("正在使用fclose()关闭文件...\n");
        fclose(fp);
    }
    
    /* 测试读取文件 */
    printf("\n正在使用open()/read()读取文件'test_output.txt'...\n");
    fd = open("test_output.txt", O_RDONLY);
    if (fd < 0) {
        perror("打开文件读取失败");
    } else {
        char buffer[TEST_BUFFER_SIZE];
        ssize_t bytes_read = read(fd, buffer, sizeof(buffer) - 1);
        if (bytes_read > 0) {
            buffer[bytes_read] = '\0';
            printf("已读取%zd字节: %s", bytes_read, buffer);
        } else {
            perror("从文件读取失败");
        }
        close(fd);
    }
}

/**
 * 测试网络操作
 */
static void test_network(void) {
    printf("\n=== 测试网络操作 ===\n");
    
    /* 创建套接字 */
    printf("正在创建套接字...\n");
    int sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (sockfd < 0) {
        perror("创建套接字失败");
        return;
    }
    
    /* 尝试连接到本地端口 */
    printf("尝试连接到127.0.0.1:%d...\n", TEST_PORT);
    struct sockaddr_in addr;
    memset(&addr, 0, sizeof(addr));
    addr.sin_family = AF_INET;
    addr.sin_port = htons(TEST_PORT);
    inet_pton(AF_INET, "127.0.0.1", &addr.sin_addr);
    
    int result = connect(sockfd, (struct sockaddr *)&addr, sizeof(addr));
    if (result < 0) {
        printf("连接失败（如果端口%d没有服务在监听则为预期结果）\n", TEST_PORT);
    } else {
        printf("连接成功\n");
        
        /* 发送一些数据 */
        const char *msg = "来自test_app的问候！";
        printf("发送消息: '%s'\n", msg);
        send(sockfd, msg, strlen(msg), 0);
        
        /* 接收响应 */
        char buffer[TEST_BUFFER_SIZE];
        ssize_t received = recv(sockfd, buffer, sizeof(buffer) - 1, 0);
        if (received > 0) {
            buffer[received] = '\0';
            printf("收到响应: %s\n", buffer);
        } else {
            printf("未收到响应\n");
        }
    }
    
    /* 关闭套接字 */
    printf("正在关闭套接字...\n");
    close(sockfd);
    
    /* 尝试连接到22端口(SSH) - 应该被钩子阻止 */
    printf("\n尝试连接到127.0.0.1:22（应被阻止）...\n");
    sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (sockfd < 0) {
        perror("创建套接字失败");
        return;
    }
    
    memset(&addr, 0, sizeof(addr));
    addr.sin_family = AF_INET;
    addr.sin_port = htons(22);  /* SSH端口 */
    inet_pton(AF_INET, "127.0.0.1", &addr.sin_addr);
    
    result = connect(sockfd, (struct sockaddr *)&addr, sizeof(addr));
    if (result < 0) {
        printf("连接被阻止（预期结果）\n");
    } else {
        printf("连接到22端口（意外结果）\n");
        close(sockfd);
    }
}

/**
 * 测试SSL/TLS操作
 */
static void test_ssl(void) {
    printf("\n=== 测试SSL/TLS操作 ===\n");
    
    /* 初始化OpenSSL库 */
    printf("初始化OpenSSL...\n");
    OPENSSL_init_ssl(0, NULL);
    ERR_load_crypto_strings();
    
    /* 创建SSL上下文 */
    printf("创建SSL上下文...\n");
    const SSL_METHOD *method = TLS_client_method();
    SSL_CTX *ctx = SSL_CTX_new(method);
    if (!ctx) {
        printf("创建SSL上下文失败\n");
        ERR_print_errors_fp(stderr);
        return;
    }
    
    /* 创建套接字 */
    printf("创建套接字...\n");
    int sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (sockfd < 0) {
        perror("创建套接字失败");
        SSL_CTX_free(ctx);
        return;
    }
    
    /* 尝试连接到外部HTTPS服务 */
    printf("尝试连接到localhost:443...\n");
    struct sockaddr_in addr;
    memset(&addr, 0, sizeof(addr));
    addr.sin_family = AF_INET;
    addr.sin_port = htons(443);  /* HTTPS端口 */
    
    /* 使用localhost避免网络问题 */
    addr.sin_addr.s_addr = inet_addr("127.0.0.1");
    
    /* 设置非阻塞模式 */
    int flags = fcntl(sockfd, F_GETFL, 0);
    fcntl(sockfd, F_SETFL, flags | O_NONBLOCK);
    
    printf("正在非阻塞模式下尝试连接...\n");
    int result = connect(sockfd, (struct sockaddr *)&addr, sizeof(addr));
    if (result < 0 && errno != EINPROGRESS) {
        perror("连接失败");
        close(sockfd);
        SSL_CTX_free(ctx);
        return;
    }
    
    /* 使用select等待连接或超时 */
    fd_set wset;
    struct timeval timeout;
    
    FD_ZERO(&wset);
    FD_SET(sockfd, &wset);
    timeout.tv_sec = 1;  /* 1秒超时 */
    timeout.tv_usec = 0;
    
    result = select(sockfd + 1, NULL, &wset, NULL, &timeout);
    if (result <= 0) {
        if (result == 0) {
            printf("连接超时\n");
        } else {
            perror("select错误");
        }
        close(sockfd);
        SSL_CTX_free(ctx);
        return;
    }
    
    /* 检查连接是否成功 */
    int error = 0;
    socklen_t len = sizeof(error);
    if (getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &error, &len) < 0 || error) {
        printf("连接错误: %s\n", strerror(error ? error : errno));
        close(sockfd);
        SSL_CTX_free(ctx);
        return;
    }
    
    /* 恢复阻塞模式 */
    fcntl(sockfd, F_SETFL, flags);
    
    printf("已连接，创建SSL对象...\n");
    
    /* 创建SSL对象 */
    SSL *ssl = SSL_new(ctx);
    SSL_set_fd(ssl, sockfd);
    
    /* 执行SSL握手 */
    printf("执行SSL握手...\n");
    
    /* 设置非阻塞模式用于SSL握手 */
    /* 重用前面已经设置的flags变量 */
    fcntl(sockfd, F_SETFL, flags | O_NONBLOCK);
    
    int ret = SSL_connect(ssl);
    if (ret <= 0) {
        int ssl_err = SSL_get_error(ssl, ret);
        if (ssl_err == SSL_ERROR_WANT_READ || ssl_err == SSL_ERROR_WANT_WRITE) {
            printf("SSL握手需要等待，使用模拟等待...\n");
            
            /* 不真正等待，因为本地没有SSL服务，模拟一下结果 */
            printf("模拟SSL握手成功，跳过实际连接\n");
            
            /* 恢复阻塞模式 */
            fcntl(sockfd, F_SETFL, flags);
            
            /* 模拟发送请求 */
            printf("模拟发送HTTPS请求...\n");
            const char *request = "HEAD / HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\n\r\n";
            printf("请求内容: %s\n", request);
            
            /* 模拟接收响应 */
            printf("模拟接收响应...\n");
            const char *simulated_response = "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\n<html><body>模拟响应</body></html>";
            printf("模拟响应: %s\n", simulated_response);
        } else {
            printf("SSL握手失败，错误码: %d\n", ssl_err);
            ERR_print_errors_fp(stderr);
        }
    } else {
        printf("SSL握手成功，使用加密方式: %s\n", SSL_get_cipher(ssl));
        
        /* 发送HTTPS请求 */
        printf("发送HTTPS请求...\n");
        const char *request = "HEAD / HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\n\r\n";
        SSL_write(ssl, request, strlen(request));
        
        /* 接收响应 */
        char buffer[TEST_BUFFER_SIZE];
        int received = SSL_read(ssl, buffer, sizeof(buffer) - 1);
        if (received > 0) {
            buffer[received] = '\0';
            printf("收到响应: %s\n", buffer);
        } else {
            printf("未收到响应\n");
        }
    }
    
    /* 清理 */
    printf("清理SSL资源...\n");
    SSL_free(ssl);
    close(sockfd);
    SSL_CTX_free(ctx);
    printf("SSL测试完成\n");
}

/**
 * 测试内存操作
 */
static void test_memory(void) {
    printf("\n=== 测试内存操作 ===\n");
    
    /* 测试malloc/free */
    printf("测试malloc/free...\n");
    void *ptr = malloc(1024);
    if (ptr) {
        printf("成功分配1024字节内存\n");
        memset(ptr, 0, 1024);
        free(ptr);
        printf("成功释放内存\n");
    } else {
        printf("内存分配失败\n");
    }
    
    /* 测试calloc */
    printf("\n测试calloc...\n");
    int *array = (int *)calloc(10, sizeof(int));
    if (array) {
        printf("成功使用calloc分配10个整数的空间\n");
        for (int i = 0; i < 10; i++) {
            array[i] = i * 10;
        }
        
        /* 测试realloc */
        printf("\n测试realloc...\n");
        int *new_array = (int *)realloc(array, 20 * sizeof(int));
        if (new_array) {
            printf("成功使用realloc将数组扩展到20个整数\n");
            array = new_array;
            for (int i = 10; i < 20; i++) {
                array[i] = i * 10;
            }
        } else {
            printf("realloc失败\n");
        }
        
        free(array);
        printf("成功释放内存\n");
    } else {
        printf("calloc分配失败\n");
    }
}

/**
 * 测试环境变量拦截（供插件使用）
 */
static void test_environment(void) {
    printf("\n=== 测试环境变量拦截 ===\n");
    
    /* 获取各种环境变量 */
    const char *home = getenv("HOME");
    printf("HOME = %s\n", home ? home : "（未设置）");
    
    const char *user = getenv("USER");
    printf("USER = %s\n", user ? user : "（未设置）");
    
    const char *path = getenv("PATH");
    printf("PATH = %s\n", path ? path : "（未设置）");
    
    /* 检查插件测试变量 */
    const char *test_var = getenv("HOOK_TEST_VAR");
    printf("HOOK_TEST_VAR = %s\n", test_var ? test_var : "（未设置）");
    
    /* 显示进程ID（被插件拦截） */
    printf("\n进程ID = %d\n", getpid());
}

int main(int argc, char *argv[]) {
    /* 初始化随机数生成器 */
    srand(time(NULL));
    
    /* 打印启动消息 */
    printf("钩子框架测试应用程序\n");
    printf("==============================\n\n");
    
    /* 检查是否给定了特定测试 */
    if (argc > 1) {
        if (strcmp(argv[1], "file") == 0) {
            test_file_io();
        } 
        else if (strcmp(argv[1], "network") == 0) {
            test_network();
        } 
        else if (strcmp(argv[1], "ssl") == 0) {
            test_ssl();
        }
        else if (strcmp(argv[1], "memory") == 0) {
            test_memory();
        }
        else if (strcmp(argv[1], "env") == 0) {
            test_environment();
        }
        else {
            printf("未知测试: %s\n", argv[1]);
            printf("可用测试: file, network, ssl, memory, env\n");
        }
    } 
    else {
        /* 运行所有测试 */
        test_file_io();
        test_network();
        test_ssl();
        test_memory();
        test_environment();
    }
    
    printf("\n所有测试已完成。\n");
    
    return 0;
}
